package com.qishuihe.design;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.sun.istack.internal.NotNull;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class MyFreemarkerTemplateEngine extends AbstractTemplateEngine {

    private Configuration configuration;

    @Override
    public @NotNull
    MyFreemarkerTemplateEngine init(@NotNull ConfigBuilder configBuilder) {
        configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        configuration.setDefaultEncoding(ConstVal.UTF8);
        configuration.setClassForTemplateLoading(FreemarkerTemplateEngine.class, StringPool.SLASH);
        return this;
    }


    @Override
    public void writer(@NotNull Map<String, Object> objectMap, @NotNull String templatePath, @NotNull File outputFile) throws Exception {
        Template template = configuration.getTemplate(templatePath);
        try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {
            template.process(objectMap, new OutputStreamWriter(fileOutputStream, ConstVal.UTF8));
        }
    }


    @Override
    public @NotNull String templateFilePath(@NotNull String filePath) {
        return filePath + ".ftl";
    }

    /**
     * 输出实体文件
     *
     * @param tableInfo 表信息
     * @param objectMap 渲染数据
     * @since 3.5.0
     */
    @Override
    protected void outputEntity(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        String entityName = tableInfo.getEntityName();

        String entityPath = getPathInfo(OutputFile.entity).replace("xxx",entityName.toLowerCase());
        Map<String,Boolean> superPropertyS = new HashMap<>();
        superPropertyS.put("id",true);
        superPropertyS.put("createBy",true);
        superPropertyS.put("createDate",true);
        superPropertyS.put("updateBy",true);
        superPropertyS.put("updateDate",true);
        superPropertyS.put("enable",true);
        superPropertyS.put("tenant",true);
        objectMap.put("propertyNames",superPropertyS);
        if (StringUtils.isNotBlank(entityName) && StringUtils.isNotBlank(entityPath)) {
            getTemplateFilePath(template -> template.getEntity(getConfigBuilder().getGlobalConfig().isKotlin())).ifPresent((entity) -> {
                String entityFile = String.format((entityPath + File.separator + "%s" + suffixJavaOrKt()), entityName);
                log.info(entityFile);
                objectMap.put("superEntityClass","BaseEntity");
                objectMap.put("superEntityClassPackage","com.qishuihe.basedomain.baseentity.BaseEntity");
                outputFile(new File(entityFile), objectMap, entity);
            });
        }
    }

    /**
     * 输出Mapper文件(含xml)
     *
     * @param tableInfo 表信息
     * @param objectMap 渲染数据
     * @since 3.5.0
     */
    @Override
    protected void outputMapper(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        // MpMapper.java
        String entityName = tableInfo.getEntityName();
//        String mapperPath = getPathInfo(OutputFile.mapper);


        String mapperPath = getPathInfo(OutputFile.mapper).replace("xxx",entityName.toLowerCase());
        if (StringUtils.isNotBlank(tableInfo.getMapperName()) && StringUtils.isNotBlank(mapperPath)) {
            getTemplateFilePath(TemplateConfig::getMapper).ifPresent(mapper -> {
                String mapperFile = String.format((mapperPath + File.separator + tableInfo.getMapperName() + suffixJavaOrKt()), entityName);
                outputFile(new File(mapperFile), objectMap, mapper);
            });
        }
        // MpMapper.xml
//        String xmlPath = getPathInfo(OutputFile.mapperXml);
        String xmlPath = getPathInfo(OutputFile.mapperXml).replace("xxx",entityName.toLowerCase());
        if (StringUtils.isNotBlank(tableInfo.getXmlName()) && StringUtils.isNotBlank(xmlPath)) {
            getTemplateFilePath(TemplateConfig::getXml).ifPresent(xml -> {
                String xmlFile = String.format((xmlPath + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
                outputFile(new File(xmlFile), objectMap, xml);
            });
        }
    }

    /**
     * 输出service文件
     *
     * @param tableInfo 表信息
     * @param objectMap 渲染数据
     * @since 3.5.0
     */
    @Override
    protected void outputService(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        // IMpService.java
        String entityName = tableInfo.getEntityName();
        String servicePath = getPathInfo(OutputFile.service).replace("xxx",entityName.toLowerCase());
//        String servicePath = getPathInfo(OutputFile.service);
        if (StringUtils.isNotBlank(tableInfo.getServiceName()) && StringUtils.isNotBlank(servicePath)) {
            getTemplateFilePath(TemplateConfig::getService).ifPresent(service -> {
                String serviceFile = String.format((servicePath + File.separator + tableInfo.getServiceName() + suffixJavaOrKt()), entityName);
                outputFile(new File(serviceFile), objectMap, service);
            });
        }
        // MpServiceImpl.java
//        String serviceImplPath = getPathInfo(OutputFile.serviceImpl);
        String serviceImplPath = getPathInfo(OutputFile.serviceImpl).replace("xxx",entityName.toLowerCase());
        if (StringUtils.isNotBlank(tableInfo.getServiceImplName()) && StringUtils.isNotBlank(serviceImplPath)) {
            getTemplateFilePath(TemplateConfig::getServiceImpl).ifPresent(serviceImpl -> {
                String implFile = String.format((serviceImplPath + File.separator + tableInfo.getServiceImplName() + suffixJavaOrKt()), entityName);
                outputFile(new File(implFile), objectMap, serviceImpl);
            });
        }
    }

    /**
     * 输出controller文件
     *
     * @param tableInfo 表信息
     * @param objectMap 渲染数据
     * @since 3.5.0
     */
    @Override
    protected void outputController(@NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
        // MpController.java
        String controllerPath = getPathInfo(OutputFile.controller);

        if (StringUtils.isNotBlank(tableInfo.getControllerName()) && StringUtils.isNotBlank(controllerPath)) {
            getTemplateFilePath(TemplateConfig::getController).ifPresent(controller -> {
                String entityName = tableInfo.getEntityName();
                String controllerFile = String.format((controllerPath+ File.separator+entityName.toLowerCase() + File.separator + tableInfo.getControllerName() + suffixJavaOrKt()), entityName);
                String controllerPackage =((Map)objectMap.get("package")).get("Controller").toString();
                String applicationPackage = controllerPackage.replace("application","application"+"."+entityName.toLowerCase());
                objectMap.put("applicationPackage",applicationPackage);
                outputOutbound( controllerPath, tableInfo,  objectMap);
                outputFile(new File(controllerFile), objectMap, controller);

            });
        }
    }

    private void outputOutbound(String controllerPath,TableInfo tableInfo, @NotNull Map<String, Object> objectMap){
        String interfacePath = controllerPath.replace("application","outbound").toString();
        String entityName = tableInfo.getEntityName();
        String controllerPackage =((Map)objectMap.get("package")).get("Controller").toString();
        String interfacePackage = controllerPackage.replace("application","outbound"+"."+entityName.toLowerCase());
        String controllerFile = String.format((interfacePath+ File.separator+entityName.toLowerCase() + File.separator + "I"+entityName + suffixJavaOrKt()), entityName);
        objectMap.put("interfacePackage",interfacePackage);
        objectMap.put("interfaceName","I"+entityName);
        outputFile(new File(controllerFile), objectMap, "/mytemplates/interface.java.ftl");
    }
}
